﻿using DevExpress.ExpressApp.Blazor.Services;
using EasyXaf.EntityDesigner.BusinessObjects;
using EasyXaf.EntityDesigner.BusinessObjects.Entities;
using System.Collections.Concurrent;

namespace EasyXaf.EntityDesigner.Commands;

public class CommandManager
{
    private static readonly ConcurrentQueue<ICommand> Commands = [];

    private readonly DomainModel _domainModel;
    private readonly IXafApplicationProvider _applicationProvider;

    public CommandManager(DomainModel domainModel, IXafApplicationProvider applicationProvider)
    {
        _domainModel = domainModel;
        _applicationProvider = applicationProvider;
    }

    public ICommand ExecuteCommand(string command, CommandContext context)
    {
        if (command.Contains("//"))
        {
            command = command[..command.IndexOf("//")];
        }

        command = command?.Trim();

        if (string.IsNullOrWhiteSpace(command))
        {
            return new EmptyCommand();
        }

        var autoCommittingChanges = false;

        context ??= new CommandContext();

        if (context.ObjectSpace == null)
        {
            var application = _applicationProvider.GetApplication();
            context.ObjectSpace = application.CreateObjectSpace(typeof(Entity));
            context.DomainModel = context.ObjectSpace.GetObject(_domainModel);

            if (context.CurrentEntity != null)
            {
                context.CurrentEntity = context.ObjectSpace.GetObject(context.CurrentEntity);
            }

            autoCommittingChanges = true;
        }

        if (Commands.IsEmpty)
        {
            Commands.Enqueue(new CreateEnumCommand());
            Commands.Enqueue(new SelectEntityCommand());
            Commands.Enqueue(new CreateEntityCommand());
            Commands.Enqueue(new CreateAssociationCommand());
            Commands.Enqueue(new CreateEntityPropertyCommand());
        }

        ICommand executedCommand = null;

        foreach (var cmd in Commands)
        {
            if (cmd.CanExecute(command))
            {
                cmd.Execute(command, context);
                executedCommand = cmd;
                break;
            }
        }

        if (executedCommand == null)
        {
            throw new CommandException(command, "无法识别的命令");
        }

        if (autoCommittingChanges)
        {
            context.ObjectSpace.CommitChanges();
            context.ObjectSpace.Dispose();
        }

        return executedCommand;
    }

    public void ExecuteCommands(string[] commands, CommandContext context)
    {
        var application = _applicationProvider.GetApplication();
        var objectSpace = application.CreateObjectSpace(typeof(Entity));

        context ??= new CommandContext();
        context.DomainModel = objectSpace.GetObject(_domainModel);
        context.ObjectSpace = objectSpace;

        if (context.CurrentEntity != null)
        {
            context.CurrentEntity = objectSpace.GetObject(context.CurrentEntity);
        }

        var lineNumber = 0;

        try
        {
            foreach (var command in commands)
            {
                lineNumber++;
                ExecuteCommand(command, context);
            }
            objectSpace.CommitChanges();
        }
        catch (CommandException ex)
        {
            throw new Exception($"行号: {lineNumber}, {ex.Command}, {ex.Message}");
        }
        finally
        {
            objectSpace.Dispose();
        }
    }
}
